import mysql.connector
from datetime import datetime
import sys

# 要求说明 基于源数据库,两个客户端分别执行 1天前，2天前的sql语句。
# 1. 是基于T -1消费并且状态为 "0"  源数据库表中的sql_info的字段,  每次取10000条，需要1万当成一个事务,执行成功后将源数据表中status 修改为 1
# 2. 事务执行中 有一个出错。即事务回滚。 不写入目标数据库，并将错误记录在日志中。 当执行该事务时如执行"update","delete"语句影响行数为0时，
# 回滚该事务，不提交。并记录日志
# 3.T -2，工作原理与 T-1 相同。取前两天的数据，并且状态为 1的。

# 使用 python 3.8
# 使用了 mysql-connector-python 9.0.0 连接包


# 数据库配置
SOURCE_DB_CONFIG = {
    'host': '172.24.222.53:',
    'port': 3306,
    'user': 'report',
    'password': 'WjC#Ch&!WTUP9%7UQe7',
    'database': 'asd_lmdm_prd'
}

TARGET_DB_CONFIG01 = {
    'host': '172.24.222.13',
    'port': 3306,
    'user': 'root',
    'password': 'ES)Z+3AH&HUj',
    'database': 'asd_oms_prd'
}

TARGET_DB_CONFIG02 = {
    'host': '172.24.222.13',
    'port': 3306,
    'user': 'root',
    'password': 'ES)Z+3AH&HUj',
    'database': 'asd_lmdm_prd'
}

# 批处理大小
BATCH_SIZE = 10000


def create_error_log_table(target_conn):
    """创建错误日志表"""
    cursor = target_conn.cursor()
    create_table_sql = """
    CREATE TABLE IF NOT EXISTS sql_execution_error_log (
        id INT AUTO_INCREMENT PRIMARY KEY,
        sql_statement TEXT,
        error_message TEXT,
        execution_time DATETIME,
        batch_id VARCHAR(50)
    )
    """
    cursor.execute(create_table_sql)
    target_conn.commit()


def log_error(target_conn, sql_statement, error_msg, batch_id):
    """记录错误信息"""
    cursor = target_conn.cursor()
    insert_sql = """
    INSERT INTO sql_execution_error_log 
    (sql_statement, error_message, execution_time, batch_id)
    VALUES (%s, %s, %s, %s)
    """
    cursor.execute(insert_sql, (sql_statement, error_msg, datetime.now(), batch_id))
    target_conn.commit()


def update_source_records(source_conn, ids):
    """更新源数据库中的记录状态"""
    cursor = source_conn.cursor()
    update_sql = """
    UPDATE sql_info_lqj 
    SET state = 1, up_time = NOW()
    WHERE id IN ({}) 
    """.format(','.join(['%s'] * len(ids)))
    cursor.execute(update_sql, ids)
    source_conn.commit()


# 此处，处理数据T-1的数据
def process01_sql_batch():
    """主处理函数"""
    source_conn = mysql.connector.connect(**SOURCE_DB_CONFIG)
    target_conn01 = mysql.connector.connect(**TARGET_DB_CONFIG01)
    try:
        # 创建错误日志表 首次使用 建立表
        create_error_log_table(target_conn01)

        while True:
            source_cursor = source_conn.cursor(dictionary=True) #查询结果会以字典（dictionary）形式返回
            # 获取未处理的记录 查询昨天一整天的数据 实现 T -1
            select_sql = """
            SELECT id, sql_info 
            FROM sql_info_lqj 
            WHERE state = 0 
            AND create_time <= DATE_SUB(CURDATE(), INTERVAL 1 DAY)
            and create_time >= DATE_SUB(CURDATE(), INTERVAL 1 DAY)
            LIMIT %s
            """
            source_cursor.execute(select_sql, (BATCH_SIZE,))
            records = source_cursor.fetchall()

            if not records:
                print("没有更多需要处理的记录")
                break

            batch_id = datetime.now().strftime('%Y%m%d%H%M%S')
            target_cursor = target_conn01.cursor() # 拿到目标数据库的连接
            processed_ids = []

            try:
                # 为整个批次开启事务
                target_conn01.start_transaction()

                # 执行批次中的所有SQL
                for record in records:
                    try:
                        target_cursor.execute(record['sql_info']) # 此处执sql_info语句的内容

                        # 检查是否是UPDATE或DELETE语句
                        sql_upper = record['sql_info'].strip().upper()
                        if sql_upper.startswith(('UPDATE', 'DELETE')):
                            affected_rows = target_cursor.rowcount  # 在此处拿到update, delete 影响行数。
                            if affected_rows == 0:
                                error_msg = f"SQL语句未影响任何数据: {record['sql_info']}"
                                log_error(target_conn01, record['sql_info'], error_msg, batch_id)
                                print(f"执行出错 ID {record['id']}: {error_msg}")
                                # 回滚当前批次
                                target_conn01.rollback()
                                print(f"批次 {batch_id} 执行失败，回滚所有操作")
                                # 关闭所有连接
                                target_cursor.close()
                                source_cursor.close()
                                source_conn.close()
                                target_conn01.close()
                                # 直接退出程序
                                sys.exit(1)

                        processed_ids.append(record['id'])
                        print(f"执行SQL，ID: {record['id']}")
                    except Exception as e:
                        # 记录错误信息
                        log_error(target_conn01, record['sql_info'], str(e), batch_id)
                        print(f"执行出错 ID {record['id']}: {str(e)}")
                        # 回滚当前批次
                        target_conn01.rollback()
                        print(f"批次 {batch_id} 执行失败，回滚所有操作")
                        # 关闭所有连接
                        target_cursor.close()
                        source_cursor.close()
                        source_conn.close()
                        target_conn01.close()
                        # 直接退出程序
                        sys.exit(1)

                # 所有SQL都执行成功，提交事务
                target_conn01.commit()
                # 更新源数据库中的记录状态
                update_source_records(source_conn, processed_ids)
                print(f"批次 {batch_id} 成功处理 {len(processed_ids)} 条记录")

            except Exception as e:
                target_conn01.rollback()
                print(f"批次处理出错: {str(e)}")
                # 遇到错误时也直接退出程序
                sys.exit(1)

            finally:
                target_cursor.close()
                source_cursor.close()

    except Exception as e:
        print(f"程序执行出错: {str(e)}")
        sys.exit(1)

    finally:
        source_conn.close()
        target_conn01.close()


"""处理T-2数据的主函数"""


def process02_sql_batch():
    source_conn = mysql.connector.connect(**SOURCE_DB_CONFIG)
    target_conn02 = mysql.connector.connect(**TARGET_DB_CONFIG02)

    try:
        # 创建错误日志表
        create_error_log_table(target_conn02)

        while True:
            source_cursor = source_conn.cursor(dictionary=True)
            # 获取T-2天的状态为1的记录
            select_sql = """
            SELECT id, sql_info 
            FROM sql_info_lqj 
            WHERE state = 1 
            AND create_time <= DATE_SUB(CURDATE(), INTERVAL 2 DAY)
            AND create_time >= DATE_SUB(CURDATE(), INTERVAL 2 DAY)
            LIMIT %s
            """
            source_cursor.execute(select_sql, (BATCH_SIZE,)) #执行查询
            records = source_cursor.fetchall()

            if not records:
                print("没有更多需要处理的T-2记录")
                break

            batch_id = datetime.now().strftime('%Y%m%d%H%M%S')
            target_cursor = target_conn02.cursor()
            processed_ids = []

            try:
                # 为整个批次开启事务
                target_conn02.start_transaction()

                # 执行批次中的所有SQL
                for record in records:
                    try:
                        target_cursor.execute(record['sql_info'])

                        # 检查是否是UPDATE或DELETE语句
                        sql_upper = record['sql_info'].strip().upper()
                        if sql_upper.startswith(('UPDATE', 'DELETE')):
                            affected_rows = target_cursor.rowcount
                            if affected_rows == 0:
                                error_msg = f"SQL语句未影响任何数据: {record['sql_info']}"
                                log_error(target_conn02, record['sql_info'], error_msg, batch_id)
                                print(f"执行出错 ID {record['id']}: {error_msg}")
                                # 回滚当前批次
                                target_conn02.rollback()
                                print(f"批次 {batch_id} 执行失败，回滚所有操作")
                                # 关闭所有连接
                                target_cursor.close()
                                source_cursor.close()
                                source_conn.close()
                                target_conn02.close()
                                # 直接退出程序
                                sys.exit(1)

                        processed_ids.append(record['id'])
                        print(f"执行SQL，ID: {record['id']}")
                    except Exception as e:
                        # 记录错误信息
                        log_error(target_conn02, record['sql_info'], str(e), batch_id)
                        print(f"执行出错 ID {record['id']}: {str(e)}")
                        # 回滚当前批次
                        target_conn02.rollback()
                        print(f"批次 {batch_id} 执行失败，回滚所有操作")
                        # 关闭所有连接
                        target_cursor.close()
                        source_cursor.close()
                        source_conn.close()
                        target_conn02.close()
                        # 直接退出程序
                        sys.exit(1)

                # 所有SQL都执行成功，提交事务
                target_conn02.commit()
                # 更新源数据库中的记录状态为2
                update_source_records_to_state2(source_conn, processed_ids)
                print(f"批次 {batch_id} 成功处理 {len(processed_ids)} 条记录")

            except Exception as e:
                target_conn02.rollback()
                print(f"批次处理出错: {str(e)}")
                sys.exit(1)

            finally:
                target_cursor.close()
                source_cursor.close()

    except Exception as e:
        print(f"程序执行出错: {str(e)}")
        sys.exit(1)

    finally:
        source_conn.close()
        target_conn02.close()


def update_source_records_to_state2(source_conn, ids):
    """更新源数据库中的记录状态为2"""
    cursor = source_conn.cursor()
    update_sql = """
    UPDATE sql_info_lqj 
    SET state = 2, up_time = NOW()
    WHERE id IN ({})
    """.format(','.join(['%s'] * len(ids)))
    cursor.execute(update_sql, ids)
    source_conn.commit()


if __name__ == "__main__":
    # 先处理T-1的数据
    process01_sql_batch()
    # 再处理T-2的数据
    process02_sql_batch()
